#include "QuadTree.h"

QuadTree::QuadTree(){
	for(int i = 0; i < 4; ++i)			
		branches[i] = NULL;
	leaf = true;

}

QuadTree::~QuadTree(){

}
void QuadTree::SetNodeCenter(unsigned int x, unsigned int y){

    areaAssignedToNode.SetX(x);
    areaAssignedToNode.SetY(y);
}
void QuadTree::SetNodeDimensions(unsigned int w, unsigned int h){

    areaAssignedToNode.SetW(w);
    areaAssignedToNode.SetH(h);

}
void QuadTree::DivideLeafNode(){
	//Add 4 children serving as cross-sections of this node

	//make sure this node is a leaf
	if(IsLeaf() == false)
		return;
	
	unsigned int leaf_w = areaAssignedToNode.GetHalfOfWidth();
	unsigned int leaf_h = areaAssignedToNode.GetHalfOfHeight();

	//divide this node into four more nodes
	for(int i = 0; i < 4; ++i){
		branches[i] = new QuadTree();
		branches[i]->SetNodeDimensions(leaf_w, leaf_h);
	}
	
	unsigned int this_x = areaAssignedToNode.GetX();
	unsigned int this_y = areaAssignedToNode.GetY();
	
	branches[0]->SetNodeCenter(this_x - areaAssignedToNode.GetHalfOfWidth() * 1 / 2, this_y - areaAssignedToNode.GetHalfOfHeight() * 1 / 2);
	branches[1]->SetNodeCenter(this_x + areaAssignedToNode.GetHalfOfWidth() * 1 / 2, this_y - areaAssignedToNode.GetHalfOfHeight() * 1 / 2);
	branches[2]->SetNodeCenter(this_x + areaAssignedToNode.GetHalfOfWidth() * 1 / 2, this_y + areaAssignedToNode.GetHalfOfHeight() * 1 / 2);
	branches[3]->SetNodeCenter(this_x - areaAssignedToNode.GetHalfOfWidth() * 1 / 2, this_y + areaAssignedToNode.GetHalfOfHeight() * 1 / 2);

	leaf = false;
}
void QuadTree::DivideLeaves(){
	if(areaAssignedToNode.GetW() > MINIMUM_NODE_SIZE){
		if(!IsLeaf()){
			for(int i = 0; i < 4; i++)
				branches[i]->DivideLeaves();
		}
		else
			DivideLeafNode();    
	}
}
void QuadTree::UniteLeafNodes(){
	//combine the cross-sections (children) of this node into one leaf
	for(int i = 0; i < 4; ++i){
		delete branches[i];
		branches[i] = NULL;
	}
	leaf = true;
}
void QuadTree::RenderQuadTree(){
	LibraryInterface::DrawRect(areaAssignedToNode.GetX(), areaAssignedToNode.GetY(), areaAssignedToNode.GetW()/2, areaAssignedToNode.GetH()/2, 0, 127, 0);
	LibraryInterface::DrawCircle(areaAssignedToNode.GetX(), areaAssignedToNode.GetY(), 4, 127, 127, 0);

	for(int i = 0; i < 4; i++)
		if(!this->IsLeaf())
			branches[i]->RenderQuadTree();
	return;
}
bool QuadTree::IsLeaf(){
	return leaf;
}
void QuadTree::DestroyChildNodes(){
	for(int i = 0; i < 4; i++){
        if(branches[i] != NULL){
		    if(branches[i]->IsLeaf())
			    branches[i]->DestroyChildNodes();
		    else{
			    branches[i]->UniteLeafNodes();
		    }
        }
	}
}
QuadTree* QuadTree::GetNodeAtPoint(unsigned int x, unsigned int y){
    if(IsLeaf())
        return this;
    
    for(int i = 0; i < 4; i++)
        if(branches[i]->PointIsInsideNode(x,y))
            return branches[i]->GetNodeAtPoint(x,y);
    
}
QuadTree* QuadTree::GetNodeSurroundingRectangle(Rectangle* rect){
    if(IsLeaf())
        return this;

    for(int i = 0; i < 4; i++)
        if(branches[i]->areaAssignedToNode.AreCoordinatesWithinShape(rect->GetX()-rect->GetHalfOfWidth(), rect->GetY()-rect->GetHalfOfHeight())
            && branches[i]->areaAssignedToNode.AreCoordinatesWithinShape(rect->GetX()+rect->GetHalfOfWidth(), rect->GetY()+rect->GetHalfOfHeight()))
            return branches[i]->GetNodeSurroundingRectangle(rect);

    return this;

}
bool QuadTree::PointIsInsideNode(unsigned int x, unsigned int y){
    return areaAssignedToNode.AreCoordinatesWithinShape(x,y);
}
unsigned int QuadTree::GetX(){
    return areaAssignedToNode.GetX();
}
unsigned int QuadTree::GetY(){
    return areaAssignedToNode.GetY();
}
unsigned int QuadTree::GetW(){
    return areaAssignedToNode.GetW();
}
unsigned int QuadTree::GetH(){
    return areaAssignedToNode.GetH();
}

